home *** CD-ROM | disk | FTP | other *** search
- /* -*- Mode: C -*- */
- /* vm.cc - PageFile implementation (virtual memory management)
- * Created by Robert Heller on Sat Dec 7 00:19:52 1991
- *
- * ------------------------------------------------------------------
- * Home Libarian by Deepwoods Software
- * Common Class library implementation code
- * ------------------------------------------------------------------
- * Modification History:
- * ------------------------------------------------------------------
- * Contents:
- * ------------------------------------------------------------------
- *
- *
- * Copyright (c) 1991,1992 by Robert heller (D/B/A Deepwoods Software)
- * All Rights Reserved
- *
- */
- #include <stream.h>
- #include <vm.h>
-
- // File open function.
- // Open or create the page file
- OpenStatus PageFile::open(char *filename,Direction direction,int flags,int mode,
- Boolean create_if)
- {
- OpenStatus result = failure; // assume failure
- fd = ::open(filename,flags); // try to open the file
- // failure?
- if (fd < 0) {
- // yes. create a new file if posible
- if (create_if && (direction == out || direction == inout)) {
- #ifdef OSK
- fd = create(filename,flags,mode); // OSK specific
- #else
- fd = ::open(filename,flags|O_CREAT,mode); // vanila UNIX
- #endif
- // still a problem? give up
- if (fd < 0) return(failure);
- // else note that it is a new file
- result = opennew;
- } else return(failure);
- } else result = openold; // old file open
- PageFile::direction = direction; // remember direction
- numpagesincore = 0; // empty WS
- isopen = true; // yes, it is open
- return(result);
- }
-
- // close a PageFile
- void PageFile::close()
- {
- // if the file is open...
- if (isopen) {
- for (int i = 0; i < numpagesincore; i++) {
- // write out any dirty pages
- if (pagetable[i].isdirty) {
- if (!PageWrite(pagetable[i])) {
- int error = errno;
- cerr << "%%% PageWrite error. Page no. = " <<
- pagetable[i].diskpage.record_address <<
- "\n";
- exit(error);
- }
- pagetable[i].isdirty = false;
- }
- // free up and used core memory
- if (pagetable[i].corepage != 0) {
- delete pagetable[i].corepage;
- pagetable[i].corepage = 0;
- }
- }
- // really close the file
- ::close(fd);
- // nope, not open anymore
- isopen = false;
- // no pages core resident
- numpagesincore = 0;
- }
- }
-
- // Read in a page. ptentry says which page.
- Boolean PageFile::PageRead(PTEntry& ptentry)
- {
- //cerr << "*** PageFile::PageRead(): page's disk address is " <<
- // ptentry.diskpage.record_address << "\n";
- // try to seek to page
- long pos = lseek(fd,ptentry.diskpage.record_address,SEEK_SET);
- // can't seek? fail
- if (pos == -1L) return(false);
- // do we have memory available?
- if (ptentry.corepage == 0) {
- ptentry.corepage = new Page; // allocate memory if needed
- }
- //cerr << "*** -: page's core address is 0x" <<
- // form("%08x",ptentry.corepage) << "\n";
- // read in page
- if (read(fd,(char *)(ptentry.corepage),sizeof(Page)) <
- sizeof(Page)) return(false);
- // page is ready and clean
- ptentry.isdirty = false;
- return(true);
- }
-
- // Write out a page
- Boolean PageFile::PageWrite(PTEntry& ptentry)
- {
- //cerr << "*** PageFile::PageWrite(): page's disk address is " <<
- // ptentry.diskpage.record_address <<
- // ", and its core address is 0x" <<
- // form("%08x",ptentry.corepage) << "\n";
- // seek to disk space
- long pos = lseek(fd,ptentry.diskpage.record_address,SEEK_SET);
- // if seek failure, return failure
- if (pos == -1L) return(false);
- // write the page
- if (write(fd,(char *)(ptentry.corepage),sizeof(Page)) <
- sizeof(Page)) return(false);
- // no longer dirty...
- ptentry.isdirty = false;
- return(true);
- }
-
- // Locate a page. Read the page in if necessary, dumping the least recently
- // referenced page to make room
- PTEntry & PageFile::FindPage(DiskPage diskpage)
- {
- //cerr << "*** in PageFile::FindPage - looking for page " <<
- // diskpage.record_address << "\n";
- // is page already resident?
- for (int i = 0; i < numpagesincore; i++) {
- if (pagetable[i].diskpage == diskpage) {
- // yes. promote page to end of table, if it is not
- // already there
- //cerr << "*** -: Page is resident.\n";
- if (i < (numpagesincore-1)) {
- temp = pagetable[i];
- for (int j = i+1; j < numpagesincore; j++) {
- pagetable[j-1] = pagetable[j];
- }
- pagetable[numpagesincore-1] = temp;
- }
- //cerr << "*** -: core address is 0x" <<
- // form("%08x",pagetable[numpagesincore-1].corepage) <<
- // "\n";
- // return page table entry
- return(pagetable[numpagesincore-1]);
- }
- }
- //cerr << "*** -: Page is non-resident.\n";
- // page not in core. Is WS (page table) full?
- if (numpagesincore < NumPTEntries) {
- //cerr << "*** -: WS grown.\n";
- // if not, use new entry at the end and increase WS
- pagetable[numpagesincore].diskpage = diskpage;
- if (!PageRead(pagetable[numpagesincore])) {
- int error = errno;
- cerr << "%%% PageRead error: page no. = " <<
- diskpage.record_address << "\n";
- exit(error);
- }
- numpagesincore++;
- //cerr << "*** -: core address is 0x" <<
- // form("%08x",pagetable[numpagesincore-1].corepage) <<
- // "\n";
- return(pagetable[numpagesincore-1]);
- } else { // otherwise, bump a page
- // if old page is dirty, write it out
- if (pagetable[0].isdirty == true) {
- //cerr << "*** -: Page out " <<
- // pagetable[0].diskpage.record_address <<
- // "\n";
- if (!PageWrite(pagetable[0])) {
- int error = errno;
- cerr << "%%% PageWrite error: page no. = " <<
- pagetable[0].diskpage.record_address <<
- "\n";
- exit(error);
- }
- }
- // shift pages down
- temp = pagetable[0];
- for (int j = 1; j < numpagesincore; j++) {
- pagetable[j-1] = pagetable[j];
- }
- pagetable[numpagesincore-1] = temp;
- // setup page
- pagetable[numpagesincore-1].diskpage = diskpage;
- if(!PageRead(pagetable[numpagesincore-1])) {
- int error = errno;
- cerr << "%%% PageRead error: page no. = " <<
- diskpage.record_address << "\n";
- exit(error);
- }
- //cerr << "*** -: core address is 0x" <<
- // form("%08x",pagetable[numpagesincore-1].corepage) <<
- // "\n";
- return(pagetable[numpagesincore-1]);
- }
- }
-
- // allocate a new, fresh page
- DiskPage PageFile::NewPage()
- {
- DiskPage temppage; // new page
- long int fill; // filler to make page address fall
- // on a sector boundry
- static char buffer[SectorSize]; // filler
- static Boolean init = false; // init flag
- if (init == false) { // filler initialization
- memset(buffer,'\0',SectorSize);
- init = true;
- }
- //cerr << "*** in PageFile::NewPage()\n";
- // find eof
- temppage = lseek(fd,0,SEEK_END);
- if (temppage == -1L) return temppage; // failure??
- // compute filler size
- fill = SectorSize - (temppage.record_address & (SectorSize-1));
- // is filler even needed?
- if (fill == SectorSize) fill = 0;
- if (fill != 0) {
- // yep. write filler and re-compute page address.
- write(fd,buffer,fill);
- temppage = lseek(fd,0,SEEK_END);
- }
- //cerr << "*** -: new page at " << temppage.record_address << "\n";
- // find a home for this page (code copied from FindPage, with
- // minor mode)
- if (numpagesincore < NumPTEntries) {
- //cerr << "*** -: WS grown.\n";
- pagetable[numpagesincore].diskpage = temppage;
- if (pagetable[numpagesincore].corepage == 0) {
- pagetable[numpagesincore].corepage = new Page;
- }
- //cerr << "*** -: core address is 0x" <<
- // form("%08x",pagetable[numpagesincore].corepage) <<
- // "\n";
- memset((char *) pagetable[numpagesincore].corepage,
- '\0',SectorSize);
- if (!PageWrite(pagetable[numpagesincore])) {
- int error = errno;
- cerr << "%%% PageWrite error: page no. = " <<
- pagetable[numpagesincore].diskpage.record_address <<
- "\n";
- exit(error);
- }
- pagetable[numpagesincore].isdirty = false;
- numpagesincore++;
- return(pagetable[numpagesincore-1].diskpage);
- } else {
- if (pagetable[0].isdirty == true) {
- //cerr << "*** -: Page out " <<
- // pagetable[0].diskpage.record_address <<
- // "\n";
- if (!PageWrite(pagetable[0])) {
- int error = errno;
- cerr << "%%% PageWrite error: page no. = " <<
- pagetable[0].diskpage.record_address <<
- "\n";
- exit(error);
- }
- }
- temp = pagetable[0];
- for (int j = 1; j < numpagesincore; j++) {
- pagetable[j-1] = pagetable[j];
- }
- pagetable[numpagesincore-1] = temp;
- pagetable[numpagesincore-1].diskpage = temppage;
- memset((char *) pagetable[numpagesincore-1].corepage,
- '\0',SectorSize);
- //cerr << "*** -: core address is 0x" <<
- // form("%08x",pagetable[numpagesincore-1].corepage) <<
- // "\n";
- if (!PageWrite(pagetable[numpagesincore-1])) {
- int error = errno;
- cerr << "%%% PageWrite error: page no. = " <<
- pagetable[numpagesincore-1].diskpage.record_address <<
- "\n";
- exit(error);
- }
- pagetable[numpagesincore-1].isdirty = false;
- return(pagetable[numpagesincore-1].diskpage);
- }
- }
-
- // Read in a data record
- int PageFile::ReadRecord(DiskRecord& record, char *buffer, int buffsize)
- {
- // seek to data offset
- long pos = lseek(fd,record.record_address,SEEK_SET);
- // seek failure?
- if (pos == -1) return(-1);
- // read in data (or at as much as will fit in record
- if (buffsize >= record.record_size) {
- return(read(fd,buffer,record.record_size));
- } else {
- return(read(fd,buffer,buffsize));
- }
- }
-
- // Write a redord out
- DiskRecord PageFile::WriteRecord(char *buffer, int buffsize)
- {
- DiskRecord newrec; // new disk record
- // seek to EOF
- newrec.record_address = lseek(fd,0,SEEK_END);
- // seek failure??
- if (newrec.record_address == -1L) {
- return 0;
- }
- //cerr.form("*** in WriteRecord(): newrec.record_address = 0x%08x\n",
- // newrec.record_address);
- // write out record
- newrec.record_size = write(fd,buffer,buffsize);
- //cerr.form("*** in WriteRecord(): buffsize = %d, newrec.record_size = %d\n",
- // buffsize,newrec.record_size);
- return(newrec);
- }
-
- // update old record or write new one
- DiskRecord PageFile::ReWriteRecord(DiskRecord& record, char *buffer, int buffsize)
- {
- long pos;
-
- //cerr << "*** PageFile::ReWriteRecord(): record = (:SIZE " <<
- // record.record_size << " :ADDR " << record.record_address <<
- // "), buffsize = " << buffsize << "\n";
- // will new record fill in old place?
- if (buffsize > record.record_size) {
- // no, create new record
- return(PageFile::WriteRecord(buffer,buffsize));
- } else {
- // yes, rewrite old record
- pos = lseek(fd,record.record_address,SEEK_SET);
- if (pos == -1) return(0);
- record.record_size = write(fd,buffer,buffsize);
- return(record);
- }
-
- }
-
-